
#ifndef __SRC_DISPATCHER_THREAD_POOL_H__
#define __SRC_DISPATCHER_THREAD_POOL_H__

#include <atomic>
#include <condition_variable>
#include <functional>
#include <iostream>
#include <list>
#include <memory>
#include <mutex>
#include <thread>

namespace dispatcher
{

class Task;

class Thread : public std::enable_shared_from_this<Thread>
{
public:
    using TaskSPtr = std::shared_ptr<Task>;
    using ThisType = std::shared_ptr<Thread>;

    using FinishedCallback = std::function<void(ThisType)>;

public:
    Thread(FinishedCallback callback)
      : worker_thread_(std::bind(&Thread::Run, this)), finished_callback_(callback), is_started_(false)
    {
        while (!is_started_)
            std::this_thread::yield();
    }

    ~Thread();

    void AddTask(TaskSPtr task_sptr);

    void Run();

private:
    std::thread      worker_thread_;
    FinishedCallback finished_callback_;
    TaskSPtr         task_;

    std::atomic_bool is_started_;

    std::mutex              wait_task_lock_;
    std::condition_variable conditions_;
};

namespace thread_pool
{

class ThreadPool
{
public:
    using ThisType     = std::shared_ptr<ThreadPool>;
    using TaskSPtr     = std::shared_ptr<Task>;
    using WorkerThread = std::shared_ptr<Thread>;

public:
    static ThisType GetInstance();

    bool Initialize(uint32_t max_worker_cnt = 10U)
    {
        max_workers_cnt_ = max_worker_cnt;
        return true;
    }

    bool IsAvaliable() const
    {
        return busy_workers_.size() < max_workers_cnt_;
    }

    bool Start(TaskSPtr task);

private:
    ThreadPool()                            = default;
    ThreadPool(ThreadPool const&)           = delete;
    ThreadPool(ThreadPool&&)                = delete;
    ThreadPool operator=(ThreadPool const&) = delete;

    WorkerThread CreateWorker();

    void WorkerThreadReleased(WorkerThread worker);

private:
    static ThisType         s_thread_pool_;
    std::list<WorkerThread> idle_workers_;
    std::list<WorkerThread> busy_workers_;
    uint32_t                max_workers_cnt_;
};

}  // namespace thread_pool
}  // namespace dispatcher

#endif  // __SRC_DISPATCHER_THREAD_POOL_H__
